/**
 * 
 */
package com.dalonedrau.jogl.opengl.ui.panel;

import java.util.HashMap;
import java.util.Iterator;

import com.dalonedrau.jogl.engine.Action;
import com.dalonedrau.jogl.engine.GlobalConsts;
import com.dalonedrau.jogl.engine.InputEvent;
import com.dalonedrau.jogl.engine.JOGLErrorHandler;
import com.dalonedrau.jogl.opengl.ui.Button;
import com.dalonedrau.jogl.opengl.ui.GuiComponent;
import com.dalonedrau.jogl.opengl.ui.Label;
import com.dalonedrau.jogl.opengl.ui.border.Abstract8ImageBorder;
import com.dalonedrau.jogl.opengl.ui.border.Abstract8ImageNoBackgroundBorder;
import com.dalonedrau.jogl.opengl.ui.border.GuiBorder;
import com.dalonedrau.jogl.opengl.ui.border.tabs.BottomTabbedGuiBorder;
import com.dalonedrau.jogl.opengl.ui.border.tabs.LeftTabbedGuiBorder;
import com.dalonedrau.jogl.opengl.ui.border.tabs.RightTabbedGuiBorder;
import com.dalonedrau.jogl.opengl.ui.border.tabs.TopTabbedGuiBorder;

/**
 * @author DaLoneDrau
 */
public final class TabbedPanel extends PagePanel {
	/** the background colors. */
	private float[][]						backgrounds;
	/**
	 * if true, the content appears before the tabs; otherwise the tabs are
	 * before the content.
	 */
	private boolean							contentFirst;
	/** the content panel. */
	private CardPanel						contentPanel;
	/** the list of images in the borders. */
	private String[]						tabBorders;
	/** the tab panel. */
	private Panel							tabPanel;
	/** all the tabs. */
	private HashMap<String, GuiComponent>	tabs;
	/**
	 * Creates a new instance of {@link TabbedPanel}.
	 * @param pageLayout either PAGELAYOUT_LANDSCAPE or PAGELAYOUT_PORTRAIT
	 */
	public TabbedPanel(final int pageLayout) {
		this(pageLayout, false);
	}
	/**
	 * Creates a new instance of {@link TabbedPanel}.
	 * @param pageLayout either PAGELAYOUT_LANDSCAPE or PAGELAYOUT_PORTRAIT
	 * @param contentBeforeTab if true, the content appears before the tabs;
	 *        otherwise the tabs are before the content
	 */
	public TabbedPanel(final int pageLayout, final boolean contentBeforeTab) {
		super(pageLayout,
				pageLayout == Panel.PAGELAYOUT_LANDSCAPE ?
						Panel.LANDSCAPE_TOP
						: Panel.PORTRAIT_LEFT);
		// if the panel is a landscape layout, then the tabs are on the left,
		// lined up vertically. in a portrait layout, the tabs are on top,
		// lined up from left to right
		if (super.getLayout() == Panel.PAGELAYOUT_LANDSCAPE) {
			tabPanel = new PortraitPagePanel(Panel.PORTRAIT_RIGHT);
		} else {
			tabPanel = new LandscapePagePanel(Panel.LANDSCAPE_BOTTOM);
		}
		contentFirst = contentBeforeTab;
		contentPanel = new CardPanel();
		if (contentFirst) {
			super.addChild(contentPanel);
			super.addChild(tabPanel);
		} else {
			super.addChild(tabPanel);
			super.addChild(contentPanel);
		}
		tabs = new HashMap<String, GuiComponent>();
	}
	/**
	 * Adds a tab to display.
	 * @param tab the tab component
	 * @param content the content associated with the tab
	 * @param tabName the name of the tab
	 */
	public void addTab(final GuiComponent tab, final GuiComponent content,
			final String tabName) {
		tabPanel.addChild(tab);
		contentPanel.addChild(tabName, content);
		final TabbedPanel me = this;
		if (tab instanceof Button) {
			((Button) tab).addAction(new Action() {
				/**
				 * {@inheritDoc}
				 */
				@Override
				public void performAction() {
					try {
						InputEvent.getInstance().addAction(
								me, // object
								me.getClass().getMethod(
										"showTab",
										new Class[] { String.class }
										),
								new String[] { tabName }
								);
					} catch (Exception ex) {
						JOGLErrorHandler.getInstance().fatalError(ex);
					}
				}
			});
		} else if (tab instanceof ThreeStateButton) {
			// set the alignment for the button
			if (super.getLayout() == Panel.PAGELAYOUT_LANDSCAPE) {
				if (contentFirst) {
					// tabs on right - left aligned buttons
					((ThreeStateButton) tab).setHorizontalAlignment(
							GuiComponent.LEFT);
					((ThreeStateButton) tab).setVerticalAlignment(
							GuiComponent.CENTER);
				} else {
					// tabs on left - right aligned buttons
					((ThreeStateButton) tab).setVerticalAlignment(
							GuiComponent.CENTER);
					((ThreeStateButton) tab).setHorizontalAlignment(
							GuiComponent.RIGHT);
				}
			} else {
				if (contentFirst) {
					// tabs on bottom - top aligned buttons
					((ThreeStateButton) tab).setHorizontalAlignment(
							GuiComponent.CENTER);
					((ThreeStateButton) tab).setVerticalAlignment(
							GuiComponent.TOP);
				} else {
					// tabs on top - bottom aligned buttons
					((ThreeStateButton) tab).setHorizontalAlignment(
							GuiComponent.CENTER);
					((ThreeStateButton) tab).setVerticalAlignment(
							GuiComponent.BOTTOM);
				}
			}
			((ThreeStateButton) tab).getButton2().addAction(new Action() {
				/**
				 * {@inheritDoc}
				 */
				@Override
				public void performAction() {
					try {
						InputEvent.getInstance().addAction(
								me, // object
								me.getClass().getMethod(
										"showTab",
										new Class[] { String.class }
										),
								new String[] { tabName }
								);
					} catch (Exception ex) {
						JOGLErrorHandler.getInstance().fatalError(ex);
					}
				}
			});
		}
	}
	/**
	 * Creates a tab border for tab buttons that sit to the left of the content.
	 * @param tabIndex the tab's index
	 * @param insets the border insets
	 * @return {@link GuiBorder}
	 */
	private GuiBorder createLandscapeLeftTabBorder(final int tabIndex,
			final int[] insets) {
		GuiBorder brdr = null;
		if (backgrounds[tabIndex] != null) { // TAB WITH BACKGROUND
			brdr = new Abstract8ImageBorder(
					insets, // insets
					new String[] {
							tabBorders[GlobalConsts.CORNER_00BOTTOM_LEFT], // bl
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // b
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // br
							tabBorders[GlobalConsts.CORNER_03LEFT], // l
							"clearpixel", // r
							tabBorders[GlobalConsts.CORNER_05TOP_LEFT], // tl
							tabBorders[GlobalConsts.CORNER_06TOP], // t
							tabBorders[GlobalConsts.CORNER_06TOP] // tr
					},
									backgrounds[tabIndex]);
		} else {
			// TAB WITH NO BACKGROUND
			brdr = new Abstract8ImageNoBackgroundBorder(
					insets, // insets
					new String[] {
							tabBorders[GlobalConsts.CORNER_00BOTTOM_LEFT], // bl
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // b
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // br
							tabBorders[GlobalConsts.CORNER_03LEFT], // l
							"clearpixel", // r
							tabBorders[GlobalConsts.CORNER_05TOP_LEFT], // tl
							tabBorders[GlobalConsts.CORNER_06TOP], // t
							tabBorders[GlobalConsts.CORNER_06TOP] // tr
					}
					);
		}
		return brdr;
	}
	/**
	 * Creates a tab border for tab buttons that sit to the right of the
	 * content.
	 * @param tabIndex the tab's index
	 * @param insets the border insets
	 * @return {@link GuiBorder}
	 */
	private GuiBorder createLandscapeRightTabBorder(final int tabIndex,
			final int[] insets) {
		GuiBorder brdr = null;
		if (backgrounds[tabIndex] != null) {
			brdr = new Abstract8ImageBorder(
					insets, // insets
					new String[] {
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // bl
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // b
							tabBorders[GlobalConsts.CORNER_02BOTTOM_RIGHT], // br
							"clearpixel", // l
							tabBorders[GlobalConsts.CORNER_04RIGHT], // r
							tabBorders[GlobalConsts.CORNER_06TOP], // tl
							tabBorders[GlobalConsts.CORNER_06TOP], // t
							tabBorders[GlobalConsts.CORNER_07TOP_RIGHT] // tr
					},
					backgrounds[tabIndex]
					);
		} else {
			brdr = new Abstract8ImageNoBackgroundBorder(
					insets, // insets
					new String[] {
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // bl
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // b
							tabBorders[GlobalConsts.CORNER_02BOTTOM_RIGHT], // br
							"clearpixel", // l
							tabBorders[GlobalConsts.CORNER_04RIGHT], // r
							tabBorders[GlobalConsts.CORNER_06TOP], // tl
							tabBorders[GlobalConsts.CORNER_06TOP], // t
							tabBorders[GlobalConsts.CORNER_07TOP_RIGHT] // tr
					}
					);

		}
		return brdr;
	}
	/**
	 * Creates a tab border for tab buttons that sit below the content.
	 * @param tabIndex the tab's index
	 * @param insets the border insets
	 * @return {@link GuiBorder}
	 */
	private GuiBorder createPortraitBottomTabBorder(final int tabIndex,
			final int[] insets) {
		GuiBorder brdr = null;
		if (backgrounds[tabIndex] != null) {
			brdr = new Abstract8ImageBorder(
					insets, // insets
					new String[] {
							tabBorders[GlobalConsts.CORNER_00BOTTOM_LEFT], // bl
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // b
							tabBorders[GlobalConsts.CORNER_02BOTTOM_RIGHT], // br
							tabBorders[GlobalConsts.CORNER_03LEFT], // l
							tabBorders[GlobalConsts.CORNER_04RIGHT], // r
							tabBorders[GlobalConsts.CORNER_03LEFT], // tl
							"clearpixel", // t
							tabBorders[GlobalConsts.CORNER_04RIGHT] // tr
					},
					backgrounds[tabIndex]);
		} else {
			brdr = new Abstract8ImageNoBackgroundBorder(
					insets, // insets
					new String[] {
							tabBorders[GlobalConsts.CORNER_00BOTTOM_LEFT], // bl
							tabBorders[GlobalConsts.CORNER_01BOTTOM], // b
							tabBorders[GlobalConsts.CORNER_02BOTTOM_RIGHT], // br
							tabBorders[GlobalConsts.CORNER_03LEFT], // l
							tabBorders[GlobalConsts.CORNER_04RIGHT], // r
							tabBorders[GlobalConsts.CORNER_03LEFT], // tl
							"clearpixel", // t
							tabBorders[GlobalConsts.CORNER_04RIGHT] // tr
					}
					);
		}
		return brdr;
	}
	/**
	 * Creates a tab border for tab buttons that sit above the content.
	 * @param tabIndex the tab's index
	 * @param insets the border insets
	 * @return {@link GuiBorder}
	 */
	private GuiBorder createPortraitTopTabBorder(final int tabIndex,
			final int[] insets) {
		GuiBorder brdr = null;
		if (backgrounds[tabIndex] != null) {
			brdr = new Abstract8ImageBorder(
					insets, // insets
					new String[] {
							tabBorders[GlobalConsts.CORNER_03LEFT], // bl
							"clearpixel", // b
							tabBorders[GlobalConsts.CORNER_04RIGHT], // br
							tabBorders[GlobalConsts.CORNER_03LEFT], // l
							tabBorders[GlobalConsts.CORNER_04RIGHT], // r
							tabBorders[GlobalConsts.CORNER_05TOP_LEFT], // tl
							tabBorders[GlobalConsts.CORNER_06TOP], // t
							tabBorders[GlobalConsts.CORNER_07TOP_RIGHT] // tr
					},
					backgrounds[tabIndex]);
		} else {
			brdr = new Abstract8ImageNoBackgroundBorder(
					insets, // insets
					new String[] {
							tabBorders[GlobalConsts.CORNER_03LEFT], // bl
							"clearpixel", // b
							tabBorders[GlobalConsts.CORNER_04RIGHT], // br
							tabBorders[GlobalConsts.CORNER_03LEFT], // l
							tabBorders[GlobalConsts.CORNER_04RIGHT], // r
							tabBorders[GlobalConsts.CORNER_05TOP_LEFT], // tl
							tabBorders[GlobalConsts.CORNER_06TOP], // t
							tabBorders[GlobalConsts.CORNER_07TOP_RIGHT] // tr
					}
					);
		}
		return brdr;
	}
	/**
	 * Displays a specific tab. Wrapper for method {@see showTab}.
	 * @param tab the tab to display.
	 */
	public void displayTab(final String tab) {
		showTab(tab);
	}
	/**
	 * Gets the number of tabs/
	 * @return <code>int</code>
	 */
	public int getNumTabs() {
		return tabPanel.getChildren().length;
	}
	/**
	 * Gets a specific tab by its index.
	 * @param index the tab's index
	 * @return {@link GuiComponent}
	 */
	public GuiComponent getTab(final int index) {
		return tabPanel.getChildren()[index];
	}
	/**
	 * Sets the borders the panel uses.
	 * @param newTabBorders the list of border images used
	 * @param bkgs a 2-dimensional array of background colors used. each tab
	 *        gets its own background color, or null for no background
	 * @param tabInsets the insets for the tab borders
	 * @param contentInsets the insets for the content borders
	 */
	public void setBorder(final String[] newTabBorders, final float[][] bkgs,
			final int[] tabInsets, final int[] contentInsets) {
		try {
			backgrounds = bkgs;
			tabBorders = newTabBorders;
			if (super.getLayout() == Panel.PAGELAYOUT_LANDSCAPE) {
				if (contentFirst) {
					// set left inset to 0
					tabInsets[1] = 0;
				} else {
					// set right inset to 0
					tabInsets[GlobalConsts.INT_003] = 0;
				}
			} else {
				if (contentFirst) {
					// set top inset to 0
					tabInsets[0] = 0;
				} else {
					// set bottom inset to 0
					tabInsets[2] = 0;
				}
			}
			// fix the borders for the tabs
			for (int i = 0; i < tabPanel.getChildren().length; i++) {
				GuiComponent tab = tabPanel.getChildren()[i];
				GuiComponent content = contentPanel.getChildren()[i];
				if (tab instanceof ThreeStateButton) {
					// 1st label gets no border
					// 2nd button gets no border
					// 3rd label gets border
					// create border
					Label lbl = ((ThreeStateButton) tab).getLabel3();
					if (super.getLayout() == Panel.PAGELAYOUT_LANDSCAPE) {
						if (contentFirst) {
							int pos = GuiComponent.TAB_MIDDLE;
							if (i == 0) {
								pos = GuiComponent.TAB_FIRST;
							}
							// content first, buttons are to right of content
							lbl.setBorder(createLandscapeRightTabBorder(i,
									tabInsets));
							content.setBorder(new RightTabbedGuiBorder(
									contentInsets, // insets
									newTabBorders, // borders
									backgrounds[i], // background color
									pos, // tab position
									tab // tab button
							));
						} else {
							int pos = GuiComponent.TAB_MIDDLE;
							if (i == 0) {
								pos = GuiComponent.TAB_FIRST;
							}
							// content last, buttons are to left of content
							lbl.setBorder(createLandscapeLeftTabBorder(i,
									tabInsets));
							content.setBorder(new LeftTabbedGuiBorder(
									contentInsets, // insets
									newTabBorders, // borders
									backgrounds[i], // background color
									pos, // tab position
									tab // tab button
							));
						}
					} else {
						if (contentFirst) {
							int pos = GuiComponent.TAB_MIDDLE;
							if (i == 0) {
								pos = GuiComponent.TAB_FIRST;
							}
							// content first, buttons are to right of content
							lbl.setBorder(createPortraitBottomTabBorder(i,
									tabInsets));
							content.setBorder(new BottomTabbedGuiBorder(
									contentInsets, // insets
									newTabBorders, // borders
									backgrounds[i], // background color
									pos, // tab position
									tab // tab button
							));
						} else {
							int pos = GuiComponent.TAB_MIDDLE;
							if (i == 0) {
								pos = GuiComponent.TAB_FIRST;
							}
							// content last, buttons are to left of content
							lbl.setBorder(createPortraitTopTabBorder(i,
									tabInsets));
							content.setBorder(new TopTabbedGuiBorder(
									contentInsets, // insets
									newTabBorders, // borders
									backgrounds[i], // background color
									pos, // tab position
									tab // tab button
							));
						}
					}
					((ThreeStateButton) tab).addChild("3", lbl);
				}
			}
			super.setPreferredSize(0, 0);
			tabPanel.setPreferredSize(0, 0);
			contentPanel.setPreferredSize(0, 0);
			super.getPreferredSize();
			for (int i = 0; i < contentPanel.getChildren().length; i++) {
				if (super.getLayout() == Panel.PAGELAYOUT_LANDSCAPE) {
					if (contentFirst) {
						RightTabbedGuiBorder brdr = (RightTabbedGuiBorder)
								contentPanel.getChildren()[i].getBorder();
						if (brdr != null) {
							brdr.setPreferredSize(
									contentPanel.getPreferredSize().width,
									contentPanel.getPreferredSize().height,
									this,
									i
									);
						}
					} else {
						LeftTabbedGuiBorder brdr = (LeftTabbedGuiBorder)
								contentPanel.getChildren()[i].getBorder();
						if (brdr != null) {
							brdr.setPreferredSize(
									contentPanel.getPreferredSize().width,
									contentPanel.getPreferredSize().height,
									this,
									i
									);
						}
					}
				} else {
					if (contentFirst) {
						BottomTabbedGuiBorder brdr = (BottomTabbedGuiBorder)
								contentPanel.getChildren()[i].getBorder();
						if (brdr != null) {
							brdr.setPreferredSize(
									contentPanel.getPreferredSize().width,
									contentPanel.getPreferredSize().height,
									this,
									i
									);
						}
					} else {
						TopTabbedGuiBorder brdr = (TopTabbedGuiBorder)
								contentPanel.getChildren()[i].getBorder();
						if (brdr != null) {
							brdr.setPreferredSize(
									contentPanel.getPreferredSize().width,
									contentPanel.getPreferredSize().height,
									this,
									i
									);
						}
					}
				}
			}
			if (super.getPosition() != null) {
				super.setPosition(
						super.getPosition().getX(),
						super.getPosition().getY(),
						super.getPosition().getZ());
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	public void showTab(final String tabName) {
		contentPanel.displayChild(tabName);
		// switch tabs
		Iterator<String> iter = tabs.keySet().iterator();
		while (iter.hasNext()) {
			String s = iter.next();
			GuiComponent tab = tabs.get(s);
			if (s.equalsIgnoreCase(tabName)) {} else {
				// set all except selected tab to show inactive display
				if (tab instanceof ThreeStateButton) {
					((ThreeStateButton) tab).displayChild("1");
				}
			}
		}
	}
	/**
	 * Displays a specific tab. Wrapper for method {@see showTab}.
	 * @param tab the tab to display.
	 */
	public void switchToTab(final String tab) {
		showTab(tab);
	}
}
